package com.axend.vetwavve.helper

import android.graphics.Bitmap
import android.os.Environment
import android.util.Log
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.opencv.android.OpenCVLoader
import org.opencv.android.Utils
import org.opencv.core.Core
import org.opencv.core.Mat
import org.opencv.core.MatOfFloat
import org.opencv.core.MatOfInt
import org.opencv.core.Rect
import org.opencv.imgcodecs.Imgcodecs
import org.opencv.imgproc.Imgproc
import javax.security.auth.callback.Callback

class MotionDetectHelper {

    init {
        if (OpenCVLoader.initLocal()) {
            Log.i("MotionDetectHelper", "OpenCV loaded successfully")
        } else {
            Log.e("MotionDetectHelper", "OpenCV initialization failed!")
        }
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////
    private var previousFrame: Mat? = null
    private var currentFrame: Mat? = null
    private var targetRect: Rect? = null
    private var frameCount = 0
    private var savePosition = 0

    constructor()

    constructor(rect: Rect) {
        this.targetRect = rect
    }

    /**
     * process Infrared Thermal Imaging Target Motion
     */
    fun processThermalImagingTargetMotion(
        p0: Bitmap?,
        threshValue: Double = 50.0,
        moveMaxValue: Int = 2500,
        callback: (Int) -> Unit
    ): Bitmap? {

        previousFrame = previousFrame ?: Mat()
        currentFrame = currentFrame ?: Mat()

        frameCount++
        if (frameCount % 3 == 0) {
            // 在这里检查前一帧是否为空
            if (previousFrame!!.empty()) {//为空的话将当前帧赋值给他
                Utils.bitmapToMat(p0, previousFrame)
                return p0;
            }
            Utils.bitmapToMat(p0, currentFrame)

            // 在指定的矩形框中进行帧差法（小猫头部外圈的框框）
            val currentRoi = Mat(currentFrame, targetRect) //框框内当前图
            val previousRoi = Mat(previousFrame, targetRect) //框框内上一帧图

            GlobalScope.launch(Dispatchers.Main) {
//                delay(10000) // 延迟 1000 毫秒（1 秒）
                if (savePosition < 10) {
                    // 保存 currentRoi 到文件
                    Imgcodecs.imwrite(
                        "${Environment.getExternalStorageDirectory().absolutePath}/currentRoi_$savePosition.png",
                        currentRoi
                    )

                    // 保存 previousRoi 到文件
                    Imgcodecs.imwrite(
                        "${Environment.getExternalStorageDirectory().absolutePath}/previousRoi_$savePosition.png",
                        previousRoi
                    )
                    savePosition++
                }
            }

            val diff = Mat() // 框框内差异图
            val currentRoiGray = Mat() // 框框内当前帧灰度图
            val previousRoiGray = Mat() // 框框内上一帧灰度图
            Imgproc.cvtColor(currentRoi, currentRoiGray, Imgproc.COLOR_RGBA2GRAY);
            Imgproc.cvtColor(previousRoi, previousRoiGray, Imgproc.COLOR_RGBA2GRAY);

            //计算当前帧与前一帧在目标区域内的差异(绝对差值) //两帧之间变化的像素点，变化较大的像素表示较大移动可能性的存在
            Core.absdiff(
                currentRoiGray,
                previousRoiGray,
                diff
            )
            // 动态找到最优阈值
            val optimalThreshold = findOptimalThreshold(diff)
            //将差异图像 diff 二值化，忽略小变化，凸显比较明显的变化
            Imgproc.threshold(
                diff,
                diff,
                optimalThreshold,
                255.0,
                Imgproc.THRESH_BINARY
            )
//            Imgproc.threshold(diff, diff, 0.0, 255.0, Imgproc.THRESH_BINARY + Imgproc.THRESH_OTSU)

            //二值化图像可以更容易地检测变化区域，忽略小的光照变化或者噪声。（大于阈值的区域可能有移动的部分存在）
            //Imgproc.threshold 函数将 diff差异图 中的像素值与阈值 25.0 进行比较。如果像素值大于 25.0，则将该像素设为 255白色 否则设为 0黑色。从而形成二值图像
            // 保存 currentRoi 到文件
            if (savePosition<10){
                Imgcodecs.imwrite(
                    "${Environment.getExternalStorageDirectory().absolutePath}/二值_diff_${savePosition-1}.png",
                    diff
                )
            }
            // 计算差异区域的非零像素（移动区域）
            val movement = Core.countNonZero(diff)//计算图像中非零像素的数量
            callback(movement)
            //val movementRatio = movement.toDouble() / (targetRect.width * targetRect.height) //非零像素的占比(非零像素在矩形区域中的占比)
            if (movement > moveMaxValue) { // 后期测试根据实际需要调整阀值
                Log.d("MotionDetectHelper", "K移动K")
            }


            diff.release()
            currentRoiGray.release()
            currentRoiGray.release()
            previousFrame!!.release()

            //更新前一帧为当前帧
            currentFrame!!.copyTo(previousFrame)
//            previousFrame = currentFrame!!.clone()

            return p0
        } else {
            currentFrame!!.release()
            Utils.bitmapToMat(p0, currentFrame)
            previousFrame!!.release()
            Utils.bitmapToMat(p0, previousFrame)
            return p0
        }
    }

    private fun findOptimalThreshold(diff: Mat): Double {
        val hist = Mat()
        val histSize = 256
        val range = MatOfFloat(0f, 256f)
        val channels = MatOfInt(0)
        val mask = Mat()

        // 计算直方图
        Imgproc.calcHist(listOf(diff), channels, mask, hist, MatOfInt(1), range)

        // 找到直方图中的峰值
        var maxVal = 0.0
        var optimalThreshold = 0.0
        for (i in 0 until histSize) {
            val value = hist.get(i, 0)[0]
            if (value > maxVal) {
                maxVal = value
                optimalThreshold = i.toDouble()
            }
        }

        return optimalThreshold
    }

    fun release() {
        previousFrame?.release()
        currentFrame?.release()
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
}
